package se.rkrantz.simpleraid.service.raid;

import java.util.ArrayList;
import java.util.List;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import se.rkrantz.simpleraid.hibernate.dao.RaidDao;
import se.rkrantz.simpleraid.hibernate.dao.SignupDao;
import se.rkrantz.simpleraid.hibernate.dao.WowCharacterDao;
import se.rkrantz.simpleraid.hibernate.domain.Raid;
import se.rkrantz.simpleraid.hibernate.domain.Signup;
import se.rkrantz.simpleraid.hibernate.domain.Signup.Role;
import se.rkrantz.simpleraid.hibernate.domain.Signup.Status;
import se.rkrantz.simpleraid.hibernate.domain.WowCharacter;
import se.rkrantz.simpleraid.web.controller.raid.Day;
import se.rkrantz.simpleraid.web.controller.raid.Week;

@Service
public class RaidService {
	@Autowired private RaidDao raidDao;
	@Autowired private WowCharacterDao wowCharacterDao;
	@Autowired private SignupDao signupDao;
	
	/**
	 * Method for creating a raid with a title on a specific date
	 * 
	 * @param raidTitle The title of the raid
	 * @param raidDate The date of the raid. (yyyy-MM-dd)
	 */
	public void createRaid(String raidTitle, String raidDate) {
		DateTime dt = DateTime.parse(raidDate);
		
		Raid raid = new Raid();
		raid.setRaidTitle(raidTitle);
		raid.setRaidDate(dt);
		
		raidDao.save(raid);
	}
	
	/**
	 * Method for getting all raids between two dates.
	 * 
	 * @param start The earliest date for getting raids.
	 * @param end The last date for getting raids.
	 * @return A list of raids between the start and end dates.
	 */
	public List<?> getRaids(DateTime start, DateTime end) {
		List<Raid> raids = new ArrayList<Raid>();
		
		raids = raidDao.getRaidsBetweenDates(start, end);
		
		return raids;
	}
	
	public Raid getRaid(long raidId) {
		
		Raid raid = raidDao.findRaidById(raidId);
		
		return raid;
	}
	
	public WowCharacter getCharacter(long characterId) {
		return wowCharacterDao.findByCharacterById(characterId);
	}
	
	public void signupToRaid(long raidId, long characterId, String role, String status) {
		Raid raid = getRaid(raidId);
		WowCharacter character = getCharacter(characterId);
		
		Signup signup = new Signup();
		signup.setRole(Role.valueOf(role));
		signup.setStatus(Status.valueOf(status));
		signup.setSignedBy(character);
		
		signupDao.save(signup);
		raid.addSignup(signup);
		raidDao.update(raid);
	}
	
	/**
	 * Returns four weeks.
	 * 
	 * @return A list of four Week objects.
	 */
	public List<Week> getVisibleCalendarWeeks() {
		List<Week> weeks = new ArrayList<Week>();
		
		DateTime dt = new DateTime();
		
		// get previous week
		dt = dt.minusWeeks(1);
		int previousWeek = dt.getWeekOfWeekyear();
		weeks.add(getWeekObject(previousWeek));
		
		// get current week
		dt = dt.plusWeeks(1);
		int currentWeek = dt.getWeekOfWeekyear();
		weeks.add(getWeekObject(currentWeek));
		
		// get next week
		dt = dt.plusWeeks(1);
		int nextWeek = dt.getWeekOfWeekyear();
		weeks.add(getWeekObject(nextWeek));
		
		// get next next week
		dt = dt.plusWeeks(1);
		int nextnextWeek = dt.getWeekOfWeekyear();
		weeks.add(getWeekObject(nextnextWeek));

		return weeks;
	}
	
	/**
	 * Constructs a Week object for the specified week of the year.
	 * The Week object contains a list of seven Day objects that holds its own date and a 
	 * field stating if that date is the current date.
	 * 
	 * @param week The week for which to construct the Week object.
	 * @return The Week object.
	 */
	private Week getWeekObject(int week) {
		Week weekObject = new Week();
		weekObject.setWeekNumber(week);
		
		List<Day> daysOfWeek = new ArrayList<Day>();
		
		for (int i = 1; i <= 7; i++) {
			DateTime dt = new DateTime();
			dt = dt.withWeekOfWeekyear(week);
			dt = dt.withDayOfWeek(i);
			
			Day day = new Day();
			day.setDate(dt);
			day.setToday(dt.getDayOfYear() == (new DateTime()).getDayOfYear());
			
			daysOfWeek.add(day);
		}
		
		weekObject.setWeekdays(daysOfWeek);
		
		return weekObject;
	}
}
